from typing import Optional

from tortoise import Tortoise

from crud import BaseCrud
from models import User, Role, Menu, Dict

from schema import (
    UserLogin,
    Response,
    Token,
    UserOut,
    UserIn,
    RoleIn,
    RoleOut,
    MenuIn,
    DictIn,
    DictOut,
    MenuOut,
    UserQuery,
    RoleQuery,
)
from fastapi import APIRouter, Depends

from utils import (
    verify_password,
    create_access_token,
    get_password_hash,
    list_to_tree,
    auth_token,
    api_premiss,
)

auth = APIRouter(tags=["认证"])
user = APIRouter(tags=["用户管理"])
role = APIRouter(tags=["角色管理"])
menu = APIRouter(tags=["菜单管理"])
system = APIRouter(tags=["数据字典"])
common = APIRouter(tags=["通用接口"])


@auth.post("/login", summary="登录", response_model=Response[Optional[Token]])
async def user_auth(form: UserLogin):
    if user_obj := await User.get(username=form.username, state=1):
        if verify_password(form.password, user_obj.password):
            token = create_access_token({"sub": user_obj.username})
            return Response(data=Token(id=user_obj.id, token=token))
        return Response(code=1, msg="账号或密码错误")
    return Response(code=1, msg="账号被禁用")


@user.get("/user", summary="用户列表", response_model=Response)
async def user_list(limit: int = 10, page: int = 1):
    skip = (page - 1) * limit
    result = User.filter(state__not=9).all().offset(skip).limit(limit)
    return Response(data=await UserOut.from_queryset(result))


@user.post("/user/query", summary="模糊查询")
async def user_query(form: UserQuery):
    skip = (form.page - 1) * form.limit
    limit = form.limit
    query_dict = {}
    for k, v in form.dict().items():
        if "id" not in k and v is not None and k not in ["limit", "page"]:
            query_dict[f"{k}__contains"] = v
    result = User.filter(**query_dict, state__not=9).all().offset(skip).limit(limit)
    return Response(data=await UserOut.from_queryset(result))


@user.post("/user", summary="用户新增", response_model=Response[Optional[UserOut]])
async def user_add(form: UserIn, prem=Depends(api_premiss)):
    if await User.filter(username=form.username).first():
        return Response(code=1, msg="用户名已存在")

    form.password = get_password_hash(form.password)
    role_objs = [await Role.get(pk=rid) for rid in form.roles]
    del form.roles

    user_obj = await User.create(**form.dict())
    await user_obj.roles.add(*role_objs)

    return Response(data=await UserOut.from_tortoise_orm(user_obj))


@user.get("/user/{pk}", summary="用户信息", response_model=Response)
async def user_info(pk: int):
    conn = Tortoise.get_connection("default")
    info = await conn.execute_query_dict(
        "select id, username, state,created, modified FROM user WHERE id = (?)", [pk]
    )
    roles = await conn.execute_query_dict(
        "select r.id, r.name, ur.status FROM role as r, user_role as ur WHERE r.id = ur.role_id AND user_id = (?)",
        [pk],
    )
    permissions = await conn.execute_query_dict(
        """
        select m.prem_tag from role_menu as rm LEFT JOIN menu as m ON rm.menu_id = m.id WHERE rm.role_id = (
        SELECT ur.role_id FROM user_role as ur WHERE ur.user_id = (?) AND ur.status = 0
        ) AND m.type = 2 AND m.prem_tag NOTNULL
        """,
        [pk],
    )
    if info:
        info[0].update({"roles": roles})
        info[0].update(
            {"permissions": [permission["prem_tag"] for permission in permissions]}
        )
        return Response(data=info[0])
    return Response(msg="用户不存在")


@user.delete("/user/{pk}", summary="删除用户", response_model=Response)
async def user_del(pk: int):
    # todo 1. 用户不存在无法删除, 2. 用户已删除状态 无法删除
    if await User.filter(pk=pk).update(state=9):
        return Response()
    return Response(msg="用户不存在")


@user.put("/user/{pk}", summary="更新用户信息", response_model=Response)
async def user_put(pk: int, form: UserIn):
    # todo 删除的角色不能选
    user_obj = await User.get(id=pk)
    form.password = get_password_hash(form.password)
    role_objs = [await Role.get(pk=rid) for rid in form.roles]
    del form.roles
    await user_obj.roles.clear()
    await user_obj.roles.add(*role_objs)
    await User.filter(id=pk).update(**form.dict())
    return Response(data=await UserOut.from_tortoise_orm(user_obj))


@role.get("/role", summary="角色列表")
async def role_list(limit: int = 10, page: int = 1):
    return Response(
        data=await RoleOut.from_queryset(BaseCrud.page_query(Role, limit, page))
    )


@role.post("/role", summary="角色新增")
async def role_list(form: RoleIn):
    role_obj = await BaseCrud.m2m_create(
        Role, form, m2=Menu, del_field="menus", m2_field="menus"
    )
    return Response(data=await RoleOut.from_tortoise_orm(role_obj))


@role.put("/role/{pk}", summary="角色更新")
async def role_put(pk: int, form: RoleIn):
    await BaseCrud.m2m_update(pk, Role, form, Menu, del_field="menus", m2_field="menus")


@role.delete("/role/{pk}", summary="角色删除")
async def role_delete(pk: int):
    await BaseCrud.delete_obj(Role, pk)
    return Response()


@role.post("/role/query", summary="检索角色列表")
async def role_query(form: RoleQuery):
    skip = (form.page - 1) * form.limit
    limit = form.limit
    delattr(form, "page")
    delattr(form, "limit")
    result = Role.filter(**form.dict(), state__not=9).all().offset(skip).limit(limit)
    return Response(data=await RoleOut.from_queryset(result))


@menu.get("/menu", summary="菜单列表")
async def menu_list(limit: int = 10, page: int = 1):
    result = BaseCrud.page_query(Menu, limit, page)
    return Response(data=await MenuOut.from_queryset(result))


@menu.post("/menu", summary="菜单新增")
async def menu_add(form: MenuIn):
    return Response(
        data=await MenuOut.from_tortoise_orm(await Menu.create(**form.dict()))
    )


@system.post("/dict", summary="字典新增")
async def dict_add(form: DictIn):
    return Response(
        data=await DictOut.from_tortoise_orm(await Dict.create(**form.dict()))
    )


@common.get("/role/{pk}/menu", summary="查询角色菜单树")
async def common_menu_tree(pk: int):
    data = await Menu.filter(roles__id=pk).all().order_by("-state").values()
    return Response(data=list_to_tree(data))


@common.put("/role/{pk}/active", summary="激活角色")
async def current_role(pk: int, obj: User = Depends(auth_token)):
    """
    select ur.user_id, ur.role_id, u.username, r.name, r.remark, ur.status FROM user as u, role as r, user_role as ur
    where u.id = ur.user_id AND ur.role_id = r.id
    """
    conn = Tortoise.get_connection("default")
    # 查出用户激活的角色，改为未激活
    sql = "select ur_id FROM user_role WHERE user_id = (?) AND status = 0"
    for ur_id in await conn.execute_query_dict(sql, [obj.id]):
        await conn.execute_query(
            "update user_role set status = 1 where ur_id = (?)", [ur_id.get("ur_id")]
        )

    await conn.execute_query(
        "update user_role set status = 0 WHERE user_id = (?) AND role_id = (?)",
        [obj.id, pk],
    )
    return Response(data=await RoleOut.from_queryset_single(Role.get(id=pk)))


@common.get("/settings", summary="系统设置", response_model=Response[DictOut])
async def get_settings():
    return Response(data=await DictOut.from_queryset_single(Dict.get(name="系统设置")))
